#ifndef __RING_QUEUE_HPP__
#define __RING_QUEUE_HPP__
#include <iostream>
#include <pthread.h>
#include <queue>
#include <semaphore.h>
#include <vector>
template <typename T>
class RingQueue
{
public:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }
    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void Unlock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap)
        : _ring_queue(cap), _cap(cap), _productor_index(0), _consumer_index(0)
    {
        sem_init(&_room_sem, 0, _cap);//信号量初始化，空间资源初始为_ring_queue的容量
        sem_init(&_data_sem, 0, 0);//数据资源初始为 0
        pthread_mutex_init(&_productor_mutex, nullptr);//互斥量初始化
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }
    void emquue(T &in)
    {
        // 生产行为
        //P操作用来减少信号量的值（通常是减1）。
        //如果_room_sem信号量的值大于0，执行P操作后，信号量的值减1，进程继续执行。
        //如果信号量的值为0，执行P操作后，进程会被阻塞，直到信号量的值变为大于0，这时进程才会被唤醒并继续执行。
        P(_room_sem);
        Lock(_productor_mutex);//加锁，维护生产者与生产者的竞争
        _ring_queue[_productor_index++] = in;//生产数据
        _productor_index %= _ring_queue.size();
        Unlock(_productor_mutex);
        V(_data_sem);//当_data_sem信号量的值增加后，如果有进程因为执行P(_data_sem)操作而被阻塞在该信号量上，
                     //那么系统会选择一个或多个进程解除其阻塞状态，允许它们继续执行
    }
    void pop(T *out)
    {
        // 消费行为
        P(_data_sem);//_data
        Lock(_consumer_mutex);
        *out = _ring_queue[_consumer_index++];
        _consumer_index %= _ring_queue.size();
        Unlock(_consumer_mutex);
        V(_room_sem);
    }
    ~RingQueue()
    {
        sem_destroy(&_room_sem);//销毁信号量
        sem_destroy(&_data_sem);
        pthread_mutex_destroy(&_productor_mutex);//销毁互斥量
        pthread_mutex_destroy(&_consumer_mutex);
    }

private:
    // 环形队列
    std::vector<T> _ring_queue;
    int _cap;
    // 生产者与消费者下标
    int _productor_index;
    int _consumer_index;
    // 信号量
    sem_t _room_sem;//空间信号量
    sem_t _data_sem;//数据信号量
    // 互斥量
    pthread_mutex_t _productor_mutex;//生产者互斥量
    pthread_mutex_t _consumer_mutex;//消费者互斥量
};
#endif